﻿using System;
using System.Collections.Generic;

using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using FSViet.Survey.Helpers;
using System.Data.SqlClient;
using System.Data;
using System.Web.UI.HtmlControls;
using log4net;

namespace FSViet.Survey
{
	public partial class Survey : System.Web.UI.Page
	{
		bool _canEdit = false;
		#region TotalQuestionOnPage

		int TotalQuestionOnPage
		{
			get
			{
				return Convert.ToInt32(Request.QueryString["TotalQuestionOnPage"]);
			}
		}
		#endregion

		#region TotalQuestion

		#endregion

		ILog _logger = LogManager.GetLogger("RollingFile");
		protected void Page_Load(object sender, EventArgs e)
		{
			//CheckCampaign();
			_logger.InfoFormat("Default page: Request URL: {0}; RefUrl: {1}", Request.Url, Request.UrlReferrer);

			if (Request.Url.DnsSafeHost != Request.UrlReferrer.DnsSafeHost)
			{
				Response.Redirect("~/Error.aspx?msg=Invalid request.");
			}
			else
			{
				bool hasError = false;

				if (Request.IsAuthenticated && (User.IsInRole("Administrators") || User.IsInRole("System administrators")))
				{ _canEdit = true; }
				else
				{
					#region validate request
					if (Request.QueryString["SiteId"] == null
						|| Request.QueryString["CampaignId"] == null
						|| Request.QueryString["Hash"] == null
						|| Request.QueryString["Sign"] == null)
					{
						hasError = true;
						Response.Redirect("~/Error.aspx?msg=Invalid request");
					}
					else
					{
						if (Request.QueryString["UserId"] == null)
						{
							hasError = true;
							Page.RegisterClientScriptBlock("GetUserSurveyInfo",
										string.Format("<script>document.location.href='VKHTCNNSurvey.aspx?SiteId={0}&CampaignId={1}&Hash={2}'</script>",
										Request.QueryString["SiteId"],
										Request.QueryString["CampignId"],
										Security.EncryptPassword(Request.QueryString["SiteId"] + "-" + Request.QueryString["CampaignId"] + "-" + Session.SessionID)));
						}
						else
						{
							var key = HttpRuntime.Cache[Request.QueryString["Sign"]];
							if (key == null)
								Response.Redirect("~/Error.aspx?msg=Invalid request. Not found key");

							//validate request
							var hash = Security.EncryptPassword(Request.QueryString["SiteId"] + "-" + Request.QueryString["CampaignId"] + "-" + Request.QueryString["UserId"] + "-" + key.ToString());
							if (hash != Request.QueryString["Hash"])
							{
								hasError = true;
								Response.Redirect("~/Error.aspx?msg=Invalid request. Invalid hash");
							}
						}
					}

					#endregion
				}

				if (!hasError)
				{
					_campaignId = new Guid(Request.QueryString["CampaignId"]);
					LoadData(_campaignId);
				}
			}
		}


		#region ViewResultMode

		public bool ViewResultMode
		{
			get
			{
				bool result = false;

				if (Request.QueryString["ViewResultMode"] != null)
					try
					{
						result = Convert.ToBoolean(Request.QueryString["ViewResultMode"]);
					}
					catch
					{
					}

				if (Session["ViewResultMode"] != null)
				{
					int reviewMode = (int)Session["ViewResultMode"];
					if (reviewMode == 1)
						result = true;
					else if (reviewMode == 2)
						result = User.Identity.IsAuthenticated;
					else if (reviewMode == 3)
						result = User.Identity.IsAuthenticated && User.IsInRole("Reporters");
				}

				return result;
			}
		}
		#endregion


		Guid _campaignId = Guid.Empty;
		DataHelper _dataH = new DataHelper();
		SqlConnection _conn = null;
		//DataTable _questions = null;
		DataRowView _questionRowView=null;
		void LoadData(Guid id)
		{
			_conn = _dataH.CreateConnection();
			try
			{
				_conn.Open();
				try
				{
					if (TotalQuestionOnPage < 1)
					{
						ShowAllQuestion(id, false);
					}
					else
					{
						var questionsView = GetQuestions();
						int totalQuestion = questionsView.Count;
						if (totalQuestion < CurrentQuestionIndex)
							ShowAllQuestion(id, true);
						else
						{
							_questionRowView = questionsView[CurrentQuestionIndex - 1];
							msg.Text = "";
							NextButton.Visible = true;
							SubmitAfterReviewButton.Visible = false;
							ShowQuestion(_questionRowView, CurrentQuestionIndex - 1, false);
							CurrentQuestionLabel.Text = CurrentQuestionIndex + "/" + totalQuestion;
						}
					}
				}
				finally
				{
					_conn.Close();
				}
			}
			catch (Exception ex)
			{
				msg.Text = ex.Message;
#if DEBUG
				msg.Text = ex.ToString().Replace("\r\n", "<br/>");
#endif
			}
		}

		void ShowQuestion(DataRowView drv, int i, bool isReview)
		{
			if (drv["QuestionType"].ToString() == "3")
			{
				//render group question
				#region render group question

				var div = new HtmlGenericControl("div");
				div.InnerHtml = "<span class='prefix'>Câu hỏi " + (i + 1) + ": </span>" + drv["Name"].ToString();

				if (_canEdit)
				{
					var item = new HtmlGenericControl("a");
					item.InnerText = " Edit group";
					item.Attributes.Add("href", "Administration/Question/Details.aspx?Id=" + drv["Id"].ToString());
					div.Controls.Add(item);

					item = new HtmlGenericControl("a");
					item.InnerText = " Sort question group";
					item.Attributes.Add("href", "Administration/Question/SortQuestion.aspx?GroupId=" + drv["Id"].ToString());
					div.Controls.Add(item);
				}
				//add group info
				SurveyFormPanel.Controls.Add(div);
				var groupId = drv["Id"].ToString();

				var questionsInGroupView = GetQuestionGroupAnswerGroup(groupId);
				foreach (DataRowView item in questionsInGroupView)
				{
					if (item["QuestionType"].ToString() == "2")
					{
						//render questions use answer group in group
						var questionUseAnswerGroupInGroup = GetQuestionUseAnswerGroup(item["Id"].ToString());
						SurveyFormPanel.Controls.Add(RenderQuestionAnswerGroup(isReview, "", item, questionUseAnswerGroupInGroup));
					}
					else
					{
						//render normal
						SurveyFormPanel.Controls.Add(RenderQuestion(isReview, "", item));
					}
				}
				//while (totalQuestionsInGroup > 0)
				//{
				//  questionInGroup = questionsInGroup.Rows[0];
				//  if (questionInGroup["AnswerGroupId"] == DBNull.Value
				//    || questionInGroup["AnswerGroupId"].ToString() == GlobalApplication.GetGuidS(Guid.Empty))
				//  {
				//    //question not use answer group
				//    SurveyFormPanel.Controls.Add(RenderQuestion(isReview, "", questionInGroup["Name"].ToString() != group["Name"].ToString(), questionInGroup));
				//    questionsInGroup.Rows.Remove(questionInGroup);
				//    totalQuestionsInGroup = questionsInGroup.Rows.Count;
				//  }
				//  else
				//  {
				//    //question use answer group
				//    var answerGroupId = questionInGroup["AnswerGroupId"].ToString();
				//    //filter all question use answer group
				//    var questionsUseAnswerGroup = GetQuestionGroupAnswerGroup(groupId, answerGroupId, questionsInGroup);
				//    totalQuestionsInGroup = questionsInGroup.Rows.Count; //update total question in group
				//    var answerGroup = _dataH.Load(_conn, "SELECT * FROM Questions WHERE Id=@Id", 0, 100,
				//      _dataH.CreateParam("Id", SqlDbType.Char, answerGroupId));
				//    //render questions use answer group
				//    SurveyFormPanel.Controls.Add(RenderQuestionAnswerGroup(isReview, "", group, answerGroup.Rows[0], questionsUseAnswerGroup));
				//  }
				//}

				#endregion
			}
			else if (drv["QuestionType"].ToString() == "2")
			{
				//render question use anwser group
				var questionUseAnswerGroups = GetQuestionUseAnswerGroup(drv["Id"].ToString());
				SurveyFormPanel.Controls.Add(RenderQuestionAnswerGroup(isReview, "Câu hỏi " + (i + 1) + ": ", drv, questionUseAnswerGroups));
			}
			else
			{
				//render normal
				SurveyFormPanel.Controls.Add(RenderQuestion(isReview, "Câu hỏi " + (i + 1) + ": ", drv));
			}
		}

		void ShowAllQuestion(Guid campaignId, bool isReview)
		{
			#region display all question

			int i = 0;
			//get top level question
			var questionView = GetQuestions();
			int totalQuestion = questionView.Count;
			
			foreach (DataRowView drv in questionView)
			{
				ShowQuestion(drv, i, isReview);
				i += 1;
			}
			
			#endregion
		}

		/// <summary>
		/// Remove all question have same group
		/// </summary>
		/// <param name="questions">Source question list</param>
		/// <param name="groupId">Must be dif with empty value</param>
		void RemoveQuestionInGroup(DataTable questions, string groupId)
		{
			int total = questions.Rows.Count;
			DataRow dr;
			for (int i = 0; i < total; )
			{
				dr = questions.Rows[i];
				if (dr["GroupId"].ToString() == groupId)
				{
					questions.Rows.RemoveAt(i);
					total = questions.Rows.Count;
				}
				else
					i++;
			}
		}

		void AddMappingQuestion(DataTable target, DataRowView dr)
		{
			var temp = target.NewRow();
			temp["Id"] = dr["Id"];
			temp["Name"] = dr["Name"];
			temp["GroupId"] = dr["GroupId"];
			temp["AnswerGroupId"] = dr["AnswerGroupId"];

			target.Rows.Add(temp);
		}

		string BuildCondiction()
		{
			string result = "";

			var answers = Answers;
			foreach (var item in answers)
			{
				if (result.IndexOf(item.QuestionId) > 1)
					continue;
				result += " AND Id!='" + item.QuestionId + "'";
			}

			return result;
		}

		/// <summary>
		/// Get question in group
		/// </summary>
		/// <param name="groupId"></param>
		/// <param name="questions"></param>
		/// <returns></returns>
		DataTable GetQuestionGroupAnswerGroup(string groupId, DataTable questions)
		{ return GetQuestionGroupAnswerGroup(groupId, "", questions); }

		DataView GetQuestions()
		{
			var table = QuestionHelper.I.Load(_campaignId);
			table.DefaultView.RowFilter = "(((QuestionType=0 OR QuestionType=1) AND GroupId='00000000000000000000000000000000' AND AnswerGroupId='00000000000000000000000000000000') OR QuestionType=3) OR (QuestionType=2 AND GroupId='00000000000000000000000000000000')";
			table.DefaultView.Sort = "OrderIndex ASC";
			return table.DefaultView;
		}

		DataView GetQuestion(string id)
		{
			var table = QuestionHelper.I.Load(_campaignId);
			table.DefaultView.RowFilter = "Id='" + id + "'";
			table.DefaultView.Sort = "OrderIndex ASC";
			return table.DefaultView;
		}

		DataView GetQuestionGroupAnswerGroup(string groupId)
		{
			var table = QuestionHelper.I.Load(_campaignId);
			table.DefaultView.RowFilter = "GroupId = '" + groupId + "' AND AnswerGroupId='00000000000000000000000000000000'";
			table.DefaultView.Sort = "OrderIndex ASC";
			return table.DefaultView;
		}

		DataView GetQuestionUseAnswerGroup(string answerGroupId)
		{
			var table = QuestionHelper.I.Load(_campaignId);
			table.DefaultView.RowFilter = "AnswerGroupId = '" + answerGroupId + "'";
			table.DefaultView.Sort = "OrderIndex ASC";
			return table.DefaultView;
		}

		DataRow FindGroup(string id, DataTable questions)
		{
			DataRow dr = null;

			for (int i = 0; i < questions.Rows.Count; i++)
			{
				if (questions.Rows[i]["Id"].ToString() == id)
				{
					dr = questions.Rows[i];
					questions.Rows.RemoveAt(i);
					break;
				}
			}

			return dr;
		}

		/// <summary>
		/// Get question in group an have the same answer group id
		/// </summary>
		/// <param name="groupId"></param>
		/// <param name="answerGroupId"></param>
		/// <param name="questions"></param>
		/// <returns></returns>
		DataTable GetQuestionGroupAnswerGroup(string groupId, string answerGroupId, DataTable questions)
		{
			DataTable result = questions.Copy();
			int index = 0;
			int mappingIndexInSource = 0;
			int totalQuestion = result.Rows.Count;
			DataRow dr;
			while (index < totalQuestion)
			{
				dr = result.Rows[index];
				if (dr["GroupId"].ToString() == groupId)
				{
					if (answerGroupId.Length > 0)
					{
						if (dr["AnswerGroupId"].ToString() == answerGroupId)
						{
							questions.Rows.RemoveAt(mappingIndexInSource);
							index += 1;
						}
						else
						{
							result.Rows.RemoveAt(index);
							totalQuestion = result.Rows.Count;
							mappingIndexInSource += 1;
						}
					}
					else
					{
						questions.Rows.RemoveAt(mappingIndexInSource);
						index += 1;
					}
				}
				else
				{
					result.Rows.RemoveAt(index);
					totalQuestion = result.Rows.Count;
					mappingIndexInSource += 1;
				}
				//if ()
			}

			return result;
		}

		/// <summary>
		/// Get answers by question id
		/// </summary>
		/// <param name="questionId"></param>
		/// <returns></returns>
		DataTable GetAnswers(string questionId)
		{
			return _dataH.Load(_conn, "SELECT * FROM Answers WHERE QuestionId=@QuestionId ORDER BY OrderIndex, Created", 0, 10,
					_dataH.CreateParam("QuestionId", SqlDbType.Char, questionId));
		}
		/// <summary>
		/// render normal question
		/// </summary>
		/// <param name="dr"></param>
		HtmlTable RenderQuestion(bool isReview, string prefix, DataRowView dr)
		{ return RenderQuestion(isReview, prefix, true, dr); }
		HtmlTable RenderQuestion(bool isReview, string prefix, bool isRenderQuestionContent, DataRowView question)
		{
			var table = new HtmlTable();
			table.ID = question["Id"].ToString();
			_logger.DebugFormat("Method: {0}; render question Id: {1}; Content: {2}", "RenderQuestion", question["Id"], question["Name"]);

			int renderAnswerMode = 1;
			if (question["RenderAnswerMode"] != DBNull.Value)
				renderAnswerMode = (int)question["RenderAnswerMode"];

			QuestionTypes type = QuestionTypes.ChoiseOne;
			if (question["QuestionType"] != DBNull.Value)
				type = (QuestionTypes)(int)question["QuestionType"];

			//load answer of question
			var answers = GetAnswers(question["Id"].ToString());
			//_dataH.Load(_conn, "SELECT * FROM Answers WHERE QuestionId=@QuestionId", 0, 10,
			//_dataH.CreateParam("QuestionId", SqlDbType.Char, dr["Id"].ToString()));

			if (renderAnswerMode == 1)
			{
				//question
				//answer 1 | answer 2 | answer 3
				#region //render on two line

				var row = new HtmlTableRow();
				var cell = new HtmlTableCell();
				if (isRenderQuestionContent)
				{
					//question content
					cell.Controls.Add(RenderQuestionControlView(question, prefix));
					//cell.InnerHtml = "<a name='" + question["Id"].ToString() + "'></a>"
					//  + (prefix.Length < 1 ? "" : "<span class='prefix'>" + prefix + ": </span>")
					//  + question["Name"].ToString();
					cell.ColSpan = answers.Rows.Count;
					row.Cells.Add(cell);
					table.Rows.Add(row);
				}
				//answers
				row = new HtmlTableRow();
				if (answers.Rows.Count < 2 && (bool)answers.Rows[0]["IsAllowComment"])
				{
					//if has one answer
					var answerRow = answers.Rows[0];
					if (answerRow["Name"].ToString() != question["Name"].ToString())
					{
						cell = new HtmlTableCell();
						cell.InnerText = answerRow["Name"].ToString();
						row.Cells.Add(cell);
					}

					cell = new HtmlTableCell();
					cell.Controls.Add(new TextBox() { ID = question["Id"].ToString() + "_" + answerRow["Id"].ToString() + "_Comment" });
					row.Cells.Add(cell);
				}
				else
				{
					foreach (DataRow item in answers.Rows)
					{
						cell = new HtmlTableCell();
						//cell.InnerHtml = item["Name"].ToString();
						cell.Controls.Add(GetAnswerControl(question["Id"].ToString() + "_" + item["Id"].ToString(), type, item["Name"].ToString(), question["Id"].ToString(), isReview ? HasCheckInCache(question["Id"].ToString(), item["Id"].ToString()) : false));
						row.Cells.Add(cell);
					}
				}

				//assign row to table
				table.Rows.Add(row);

				#endregion

				//add question to form
				//SurveyFormPanel.Controls.Add(table);
			}
			else if (renderAnswerMode == 2)
			{
				//question
				//answer 1
				//answer 2
				#region //render on two line

				var row = new HtmlTableRow();
				var cell = new HtmlTableCell();
				if (isRenderQuestionContent)
				{
					//question content
					cell.Controls.Add(RenderQuestionControlView(question, prefix));
					//cell.InnerHtml = "<a name='" + question["Id"].ToString() + "'></a>"
					//  + (prefix.Length < 1 ? "" : "<span class='prefix'>" + prefix + ": </span>")
					//  + question["Name"].ToString();
					cell.ColSpan = answers.Rows.Count;
					row.Cells.Add(cell);
					table.Rows.Add(row);
				}
				//answers
				if (answers.Rows.Count < 2 && (bool)answers.Rows[0]["IsAllowComment"])
				{
					//if has one answer
					var answerRow = answers.Rows[0];
					row = new HtmlTableRow();
					if (answerRow["Name"].ToString() != question["Name"].ToString())
					{
						cell = new HtmlTableCell();
						cell.InnerText = answerRow["Name"].ToString();
						row.Cells.Add(cell);
					}

					cell = new HtmlTableCell();
					cell.Controls.Add(new TextBox() { ID = question["Id"].ToString() + "_" + answerRow["Id"].ToString() + "_Comment" });
					row.Cells.Add(cell);
					table.Rows.Add(row);
				}
				else
				{
					foreach (DataRow item in answers.Rows)
					{
						row = new HtmlTableRow();
						cell = new HtmlTableCell();
						//cell.InnerHtml = item["Name"].ToString();
						var answerControl = GetAnswerControl(question["Id"].ToString() + "_" + item["Id"].ToString(), type, item["Name"].ToString(), question["Id"].ToString(), isReview ? HasCheckInCache(question["Id"].ToString(), item["Id"].ToString()) : false);
						if ((bool)item["IsAllowComment"])
							answerControl.ID += "_HasComment";
						cell.Controls.Add(answerControl);
						if ((bool)item["IsAllowComment"])
							cell.Controls.Add(new TextBox() { ID = question["Id"].ToString() + "_" + item["Id"].ToString() + "_Comment" });

						row.Cells.Add(cell);
						//assign row to table
						table.Rows.Add(row);
					}
				}

				#endregion

				//add question to form
				//SurveyFormPanel.Controls.Add(table);
				//
			}
			else
			{
				//question | answer 1 | answer 2 | answer 3
				#region //render on one line

				var row = new HtmlTableRow();
				var cell = new HtmlTableCell();
				if (isRenderQuestionContent)
				{
					cell.Controls.Add(RenderQuestionControlView(question, prefix));
					//question content
					//cell.InnerHtml = "<a name='" + question["Id"].ToString() + "'></a>"
					//  + (prefix.Length < 1 ? "" : "<span class='prefix'>" + prefix + ": </span>")
					//  + question["Name"].ToString();
					row.Cells.Add(cell);
				}
				//answers
				if (answers.Rows.Count < 2 && (bool)answers.Rows[0]["IsAllowComment"])
				{
					//if has one answer
					var answerRow = answers.Rows[0];
					row = new HtmlTableRow();
					if (answerRow["Name"].ToString() != question["Name"].ToString())
					{
						cell = new HtmlTableCell();
						cell.InnerText = answerRow["Name"].ToString();
						row.Cells.Add(cell);
					}

					cell = new HtmlTableCell();
					cell.Controls.Add(new TextBox() { ID = question["Id"].ToString() + "_" + answerRow["Id"].ToString() + "_Comment" });
					row.Cells.Add(cell);
					table.Rows.Add(row);
				}
				else
				{
					foreach (DataRow item in answers.Rows)
					{
						cell = new HtmlTableCell();
						//cell.InnerHtml = item["Name"].ToString();
						cell.Controls.Add(GetAnswerControl(question["Id"].ToString() + "_" + item["Id"].ToString(), type, item["Name"].ToString(), question["Id"].ToString(), isReview ? HasCheckInCache(question["Id"].ToString(), item["Id"].ToString()) : false));
						row.Cells.Add(cell);
					}
				}
				//assign row to table
				table.Rows.Add(row);

				#endregion

				//add question to form
				//SurveyFormPanel.Controls.Add(table);
			}

			return table;
		}

		Control RenderQuestionControlView(DataRowView question, string prefix)
		{
			//"<a name='" + question["Id"].ToString() + "'></a>"
			//      + (prefix.Length < 1 ? "" : "<span class='prefix'>" + prefix + ": </span>")
			//      + question["Name"].ToString()
			HtmlGenericControl result = new HtmlGenericControl("div");

			HtmlGenericControl item = new HtmlGenericControl("a");
			item.Attributes.Add("Name", question["Id"].ToString());
			result.Controls.Add(item);
			if (prefix.Length > 0)
			{
				item = new HtmlGenericControl("span");
				item.Attributes.Add("class", "prefix");
				item.InnerHtml = prefix;
				result.Controls.Add(item);
			}

			if (_canEdit)
			{
				item = new HtmlGenericControl("a");
				item.Attributes.Add("href", "Administration/Question/Details.aspx?Id=" + question["Id"].ToString());
				item.InnerHtml = question["Name"].ToString();
				result.Controls.Add(item);
			}
			else
			{
				item = new HtmlGenericControl("span");
				item.InnerHtml = question["Name"].ToString();
				result.Controls.Add(item);
			}

			return result;
		}

		#region generate question group

		HtmlTable RenderQuestionAnswerGroup(bool isReview, string prefix, DataRowView answerGroup, DataView questions)
		{
			return RenderQuestionAnswerGroup(isReview, prefix, answerGroup, questions, null);
		}
		HtmlTable RenderQuestionAnswerGroup(bool isReview, string prefix, DataRowView answerGroup, DataView questions, DataTable questionSave)
		{
			HtmlTable result = new HtmlTable();
			HtmlTableRow row;
			HtmlTableCell cell;

			DataTable answers = null;
			if (answerGroup == null)
			{ }
			else
				//get answer of answer group
				answers = GetAnswers(answerGroup["Id"].ToString());

			//if (group["Name"].ToString() != answerGroup["Name"].ToString())
			//{
				//generate answer group header
				row = new HtmlTableRow();
				cell = new HtmlTableCell();
				cell.ColSpan = answers.Rows.Count+1;
				//cell.Controls.Add(GetQuestionControlView())
				cell.InnerHtml = (prefix.Length < 1 ? "" : "<span class='prefix'>" + prefix + ": </span>")
					+ (_canEdit ? "<a href='Administration/Question/Details.aspx?Id=" + answerGroup["Id"].ToString() + "'>" : "")
					+ answerGroup["Name"].ToString()
					+ (_canEdit ? "</a>" : "");
				row.Cells.Add(cell);
				result.Rows.Add(row);
			//}

			//generate
			row = new HtmlTableRow();
			cell = new HtmlTableCell();
			cell.InnerHtml = "&nbsp;";
			row.Cells.Add(cell);
			//generate answer header
			foreach (DataRow item in answers.Rows)
			{
				cell = new HtmlTableCell();
				cell.InnerHtml = (_canEdit ? "<a href='Administration/Answer/Details.aspx?Id=" + item["Id"].ToString() + "'>" : "")
					+ item["Name"].ToString()
					+ (_canEdit ? "</a>" : "");
				cell.Align = "center";
				row.Cells.Add(cell);
			}
			result.Rows.Add(row);
			//generate question
			foreach (DataRowView item in questions)
			{
				if (questionSave != null)
					AddMappingQuestion(questionSave, item);

				result.Rows.Add(GenerateQuestionRow(isReview, true, item, answers));
			}

			return result;
		}

		/// <summary>
		/// Generate question to use answer group
		/// ----------- answer 1 | answer 2 | answer 3
		/// + question     x           x        x
		/// if isUseAnswerGroup do not render answer label 
		/// </summary>
		/// <param name="isUseAnswerGroup"></param>
		/// <param name="question"></param>
		/// <param name="answers"></param>
		/// <returns></returns>
		HtmlTableRow GenerateQuestionRow(bool isReview, bool isUseAnswerGroup, DataRowView question, DataTable answers)
		{
			HtmlTableRow result = new HtmlTableRow();
			result.ID = question["Id"].ToString();
			HtmlTableCell cell;

			//generate qestion content
			cell = new HtmlTableCell();
			_logger.DebugFormat("Method: {0}; render question Id: {1}; Content: {2}", "GenerateQuestionRow", question["Id"], question["Name"]);
			//cell.InnerHtml = "<a name='" + question["Id"].ToString() + "'></a>" + question["Name"].ToString();
			cell.Controls.Add(RenderQuestionControlView(question, ""));
			result.Cells.Add(cell);

			//generate answer
			RadioButton rad;
			foreach (DataRow item in answers.Rows)
			{
				cell = new HtmlTableCell();
				rad = new RadioButton() { ID = question["Id"].ToString() + "_" + item["Id"].ToString(), Text = isUseAnswerGroup ? "" : item["Name"].ToString(), ToolTip = item["Name"].ToString(), GroupName = question["Id"].ToString() };
				rad.Checked = isReview ? HasCheckInCache(question["Id"].ToString(), item["Id"].ToString()) : false;
				cell.Controls.Add(rad);
				cell.Align = "center";
				result.Cells.Add(cell);
			}

			return result;
		}

		#endregion

		bool HasCheckInCache(string questionId, string answerId)
		{
			bool result = false;
			var answers = Answers;
			for (int i = 0; i < answers.Count; i++)
			{
				if (answers[i].QuestionId == questionId && answers[i].AnswerId == answerId)
				{
					result = true;
					break;
				}
			}

			return result;
		}

		Control GetAnswerControl(string id, QuestionTypes type, string answer, string group, bool isChecked)
		{
			Control result = null;
			if (type == QuestionTypes.ChoiseOne)
			{
				result = new RadioButton() { ID = id, Text = answer, GroupName = group, Checked = isChecked };
			}
			else
			{
				result = new CheckBox() { ID = id, Text = answer, Checked = isChecked };
			}

			var container = new HtmlGenericControl("span");
			container.Controls.Add(result);
			container.ID = "Span_" + id;
			if (_canEdit)
			{
				id = id.Replace("_HasComment", "");
				var item = new HtmlGenericControl("a");
				item.InnerText = " Edit";
				int index = id.LastIndexOf("_");
				string url = "Administration/Answer/Details.aspx?Id=" + id.Substring(index + 1);
				index = id.IndexOf("_");
				url += "&QuestionId=" + id.Substring(0, index);
				item.Attributes.Add("href", url);
				container.Controls.Add(item);
			}
			//result.Controls.Add(item);

			//result = item;

			return container;
		}

		protected void SubmitButton_Click(object sender, EventArgs e)
		{
			bool hasError = false;
			List<Answer> answers = null;
			try
			{
				answers = CollectAnswers();
			}
			catch (Exception ex)
			{
				hasError = true;
				msg.Text = ex.Message;
#if DEBUG
				msg.Text = ex.ToString().Replace("\r\n", "<br/>");
#endif
			}

			if (!hasError)
				SaveAnswer(answers);
		}

		List<Answer> CollectAnswers()
		{
			List<Answer> result = new List<Answer>();
			//DataRow dr;
			List<CheckBox> answers;
			Control container = null;
			TextBox commentInput;
			string questionId = "";

			_conn.Open();
			try
			{
				var questions = QuestionHelper.I.Load(_campaignId);
				if (TotalQuestionOnPage < 1)
				{
					DataView dataView = questions.DefaultView;
					//for (int i = 0; i < questions.Rows.Count; i++)
					foreach (DataRowView item in dataView)
					{
						questionId = item["Id"].ToString();

						#region travel all question

						container = PageHelper.FindControlRecursive(SurveyFormPanel, questionId);
						var answersSource = GetAnswers(questionId);
						//_dataH.Load("SELECT * FROM Answers WHERE QuestionId=@QuestionId", 0, 50,
						//_dataH.CreateParam("QuestionId", SqlDbType.Char, questionId));

						if (answersSource.Rows.Count == 1 && (bool)answersSource.Rows[0]["IsAllowcomment"])
						{
							string itemId = answersSource.Rows[0]["Id"].ToString();
							//has one answer, and answer mark has comment
							//find comment control
							commentInput = PageHelper.FindControlRecursive(container, questionId + "_" + itemId + "_" + "_Comment") as TextBox;
							string comment = string.Empty;
							if (commentInput != null) comment = commentInput.Text.Trim();
							result.Add(new Answer() { QuestionId = questionId, AnswerId = itemId, Comment = comment });
						}
						else
						{
							result.AddRange(FindAnswerOfQuestion(item));
						}
						#endregion
					}
				}
				else
				{
					#region collect answer of one question or group question
					if (_questionRowView["QuestionType"].ToString() == "3")
					{
						//render group question
						#region render group question

						var groupId = _questionRowView["Id"].ToString();

						var questionsInGroupView = GetQuestionGroupAnswerGroup(groupId);
						foreach (DataRowView item in questionsInGroupView)
						{
							if (item["QuestionType"].ToString() == "2")
							{
								//render questions use answer group in group
								var questionUseAnswerGroupInGroup = GetQuestionUseAnswerGroup(item["Id"].ToString());
								foreach (DataRowView questionUseAnswerGroupInGroupView in questionUseAnswerGroupInGroup)
									result.AddRange(FindAnswerOfQuestion(questionUseAnswerGroupInGroupView));
								//SurveyFormPanel.Controls.Add(RenderQuestionAnswerGroup(isReview, "", item, questionUseAnswerGroupInGroup));
							}
							else
							{
								result.AddRange(FindAnswerOfQuestion(item));
							}
						}

						#endregion
					}
					else if (_questionRowView["QuestionType"].ToString() == "2")
					{
						//render question use anwser group
						var questionUseAnswerGroups = GetQuestionUseAnswerGroup(_questionRowView["Id"].ToString());
						foreach (DataRowView questionUseAnswerGroupInGroupView in questionUseAnswerGroups)
							result.AddRange(FindAnswerOfQuestion(questionUseAnswerGroupInGroupView));
					}
					else
					{
						//render normal
						result.AddRange(FindAnswerOfQuestion(_questionRowView));
					}
					#endregion
				}
			}
			finally
			{
				_conn.Close();
			}

			return result;
		}

		/// <summary>
		/// Find answer of question
		/// </summary>
		/// <param name="question"></param>
		/// <param name="answersSource"></param>
		List<Answer> FindAnswerOfQuestion(DataRowView question)
		{
			List<Answer> result = new List<Answer>();

			string questionId=question["Id"].ToString();
			var container = PageHelper.FindControlRecursive(SurveyFormPanel, questionId);

			var answersSource = GetAnswers(questionId);
			TextBox commentInput;

			if (answersSource.Rows.Count == 1
				&& (bool)answersSource.Rows[0]["IsAllowComment"])
			{
				//has one answer and answer has comment
				commentInput = PageHelper.FindControlRecursive(container, questionId + "_" + answersSource.Rows[0]["Id"] + "_Comment") as TextBox;
				string comment = string.Empty;
				if (commentInput != null) comment = commentInput.Text.Trim();

				if (comment.Length<1)
				{
					ClientScript.RegisterStartupScript(this.GetType(), "hash", "location.hash = '#" + questionId + "';", true);
					throw new Exception("Bạn chưa chọn câu trả lời cho câu hỏi: " + question["Name"].ToString());
				}

				result.Add(new Answer() { QuestionId = questionId, AnswerId = answersSource.Rows[0]["Id"].ToString(), Comment = comment });
			}
			else
			{
				var answers = PageHelper.FindCheckBox(container, questionId);
				if (answers.Count < 1)
				{
					ClientScript.RegisterStartupScript(this.GetType(), "hash", "location.hash = '#" + questionId + "';", true);
					throw new Exception("Bạn chưa chọn câu trả lời cho câu hỏi: " + question["Name"].ToString());
				}
				
				foreach (var item in answers)
				{
					if (item.ID.EndsWith("_HasComment"))
					{
						//find comment control
						commentInput = PageHelper.FindControlRecursive(container, questionId + "_"+item.ID + "_Comment") as TextBox;
						string comment = string.Empty;
						if (commentInput != null) comment = commentInput.Text.Trim();
						result.Add(new Answer() { QuestionId = questionId, AnswerId = item.ID.Replace(questionId + "_", "").Replace("_HasComment", ""), Comment = comment });
					}
					else
						result.Add(new Answer() { QuestionId = questionId, AnswerId = item.ID.Replace(questionId + "_", "") });
				}
			}
			return result;
		}

		//List<CheckBox> FindAllAnswer(string questionId)
		//{
		//  List<CheckBox> result = new List<CheckBox>();
		//  //find container
		//  var container = PageHelper.FindControlRecursive(SurveyFormPanel, questionId);
		//  result = PageHelper.FindCheckBox(container, questionId);

		//  return result;
		//}

		int CurrentQuestionIndex
		{
			get
			{
				int result = 1;
				if (ViewState["CurrentQuestionIndex"] != null)
					result = (int)ViewState["CurrentQuestionIndex"];
				return result;
			}
			set { ViewState["CurrentQuestionIndex"] = value; }
		}

		/// <summary>
		/// Save answer when display paging
		/// </summary>
		List<Answer> Answers
		{
			get
			{
				List<Answer> result = new List<Answer>();
				if (ViewState["Answers"] != null)
					result = (List<Answer>)ViewState["Answers"];
				return result;
			}
			set
			{
				ViewState["Answers"] = value;
			}
		}

		[Serializable]
		class Answer
		{
			public string QuestionId { get; set; }
			public string AnswerId { get; set; }
			public string Comment { get; set; }
		}

		void SaveAnswer(List<Answer> answers)
		{
			try
			{
				string siteId = GlobalApplication.GetGuidS(Guid.Empty);
				string campaignId = GlobalApplication.GetGuidS(Guid.Empty);
				string userId = GlobalApplication.GetGuidS(Guid.Empty);
#if !DEBUG
			siteId = Request.QueryString["SiteId"].ToString();
			campaignId = Request.QueryString["CampaignId"].ToString();
			userId = Request.QueryString["UserId"].ToString();
#endif
				SaveAnswer(siteId, campaignId, userId, answers);
				HttpRuntime.Cache.Remove(Request.QueryString["Sign"]);
				Response.Redirect("~/Success.aspx");
			}
			catch (Exception ex)
			{
				msg.Text = ex.Message;
#if DEBUG
				msg.Text = ex.ToString().Replace("\r\n", "<br/>");
#endif
			}
		}

		void SaveAnswer(string siteId, string campaignId, string userId, List<Answer> answers)
		{
			DataHelper dataH = new DataHelper();
			var conn = dataH.CreateConnection();
			conn.Open();
			var cmd = conn.CreateCommand();
			var trans = conn.BeginTransaction();
			cmd.Transaction = trans;
			cmd.CommandText = "INSERT INTO UserAnswers(Id, SiteId, CampaignId, UserId, QuestionId, AnswerId, Comment) VALUES(@Id, '" + siteId + "', '" + campaignId + "', '" + userId + "', @QuestionId, @AnswerId, @Comment)";
			try
			{
				foreach (var item in answers)
				{
					cmd.Parameters.Clear();
					cmd.Parameters.Add(dataH.CreateParam("Id", SqlDbType.Char, GlobalApplication.GetGuidS(Guid.NewGuid())));
					cmd.Parameters.Add(dataH.CreateParam("QuestionId", SqlDbType.Char, item.QuestionId));
					cmd.Parameters.Add(dataH.CreateParam("AnswerId", SqlDbType.Char, item.AnswerId));
					cmd.Parameters.Add(dataH.CreateParam("Comment", SqlDbType.NVarChar, item.Comment ?? ""));
					cmd.ExecuteNonQuery();
				}

				trans.Commit();
			}
			catch
			{
				trans.Rollback();
				throw;
			}
			finally
			{
				conn.Close();
			}
		}

		protected void NextButton_Click(object sender, EventArgs e)
		{
			msg.Text = "";
			//collect current question(s) data
			List<Answer> answers = null;
			try
			{
				answers = CollectAnswers();

				var currentAnswers = Answers;
				for (int i = 0; i < answers.Count; i++)
				{
					currentAnswers.Add(answers[i]);
				}

				Answers = currentAnswers;

				//clrear survey form
				SurveyFormPanel.Controls.Clear();
				//increase question index
				CurrentQuestionIndex += 1;
				//render next question
				LoadData(_campaignId);
			}
			catch (Exception ex)
			{
				msg.Text = ex.Message;
#if DEBUG
				msg.Text = ex.ToString().Replace("\r\n", "<br/>");
#endif
			}
		}

		protected void SubmitAfterReviewButton_Click(object sender, EventArgs e)
		{
			SaveAnswer(Answers);
		}
	}
}